package model

import (
	j_log "config-client-v1/init/j-log"
	"config-client-v1/utils/tools"
	"encoding/json"
	"errors"
	"fmt"
	"runtime/debug"
	"sync"
)

type ModbusServerDB struct {
	ID            int                `json:"id" gorm:"column:id"`
	ProjectID     int                `gorm:"column:project_id" json:"project_id"`
	PPEID         int                `gorm:"column:ppe_id" json:"ppe_id"`
	SlaveID       uint8              `gorm:"column:slave_id" json:"slave_id"`
	JsonDetail    string             `gorm:"column:json_detail" json:"json_detail"` // 点位关系见 ModbusPointBind
	Desc          string             `gorm:"column:desc" json:"desc"`
	CreateTime    *string            `json:"create_time" gorm:"column:create_time"`
	UpdateTime    *string            `json:"update_time" gorm:"column:update_time"`
	PointBindList []*ModbusPointBind `json:"-" gorm:"-"`
}

func (m *ModbusServerDB) TableName() string {
	return "modbus_server_db"
}

func (m *ModbusServerDB) Exists(id int) (exist bool, err error) {
	err = DB.Where("id = ?", id).Limit(1).Find(m).Error
	if err != nil {
		return
	}
	if m.ID == 0 {
		return
	}
	exist = true
	return
}

// ModbusPointBind 点位和变量绑定关系; 点位值变化时,根据SlaveID,StartAddr,Length 找到对应的变量,并更新变量值
type ModbusPointBind struct {
	PPEID        int     `json:"ppe_id"`
	SlaveID      uint8   `json:"slave_id"`      // 从站ID [0-255]
	FunctionCode string  `json:"function_code"` // [01,02,03,04]
	StartAddr    uint16  `json:"start_addr"`    // [0-65535]
	Length       uint16  `json:"length"`        // StartAddr+Length <= 65536
	Addr         string  `json:"addr"`          //
	FieldName    string  `json:"field_name"`    //
	SpecType     string  `json:"spec_type"`     //
	Endian       string  `json:"endian"`        // [big,little]默认big
	Value        float64 `json:"value"`         //
}

// ModbusValueMapStu (全局)变量和点位绑定关系; 变量值变化时,根据Addr 找到对应的点位,并更新点位值
// 设备启动和停止时 M 改动

type ModbusValueMapStu struct {
	M map[string][]*ModbusPointBind // key为Addr
	sync.RWMutex
}

func (m *ModbusValueMapStu) Get(key string) (v []*ModbusPointBind, ok bool) {
	m.RLock()
	defer m.RUnlock()
	v, ok = m.M[key]
	return
}

func (m *ModbusValueMapStu) Set(key string, v *ModbusPointBind) {
	m.Lock()
	defer m.Unlock()
	list, ok := m.M[key]
	if !ok {
		list = make([]*ModbusPointBind, 0)
		list = append(list, v)
		m.M[key] = list
	} else {
		uniqueM := make(map[string]bool)
		for _, row := range list {
			tmpKey := fmt.Sprintf("%d_%d_%s_%d", row.PPEID, row.SlaveID, row.FunctionCode, row.StartAddr)
			if uniqueM[tmpKey] {
				continue
			}
			list = append(list, row)
			uniqueM[tmpKey] = true
		}
		list = append(list, v)
		m.M[key] = list
	}
}

func (m *ModbusValueMapStu) Delete(key string) {
	m.Lock()
	defer m.Unlock()
	delete(m.M, key)
}

func ValidateModbusPointBind(projectID int, jsonDetail string) (pointList []*ModbusPointBind, err error) {
	pointList = make([]*ModbusPointBind, 0)
	err = json.Unmarshal([]byte(jsonDetail), &pointList)
	if err != nil {
		err = errors.New("点位绑定关系JSON格式错误" + err.Error())
		return
	}
	addrs := make([]string, 0)
	for _, point := range pointList {

		if int(point.StartAddr)+int(point.Length) > 65536 {
			err = errors.New(fmt.Sprintf("地址超出范围"))
			return
		}
		if point.Length == 0 {
			err = errors.New(fmt.Sprintf("长度不能为0"))
			return
		}
		if point.Addr == "" {
			err = errors.New(fmt.Sprintf("请设置关联变量"))
			return
		}
		addrs = append(addrs, point.Addr)
		if !AllowSpecType[point.SpecType] {
			err = errors.New(fmt.Sprintf("暂不支持数据类型%s", point.SpecType))
			return
		}
		if !AllowEndian[point.Endian] {
			err = errors.New(fmt.Sprintf("endian参数无效"))
			return
		}

		if point.FunctionCode == "01" {
			if point.Length != 1 {
				err = errors.New(fmt.Sprintf("线圈数量只能为1"))
				return
			}
		} else if point.FunctionCode == "02" {
			if point.Length != 1 {
				err = errors.New(fmt.Sprintf("离散输入数量只能为1"))
				return
			}
		} else if point.FunctionCode == "03" {
			if point.Length != 1 && point.Length != 2 && point.Length != 4 {
				err = errors.New(fmt.Sprintf("保持寄存器数量只能为1,2,4"))
				return
			}
		} else if point.FunctionCode == "04" {
			if point.Length != 1 && point.Length != 2 && point.Length != 4 {
				err = errors.New(fmt.Sprintf("输入寄存器数量只能为1,2,4"))
				return
			}
		} else {
			err = errors.New(fmt.Sprintf("功能码无效"))
			return
		}
	}

	if len(addrs) > 0 {
		m := make(map[string]*FrameItem)
		frameList := make([]*FrameItem, 0) // 找出所有已设置变量地址对应的变量, 和帧类型做对比用
		err = DB.Where("project_id = ? AND addr in ?", projectID, addrs).Find(&frameList).Error
		if err != nil {
			return
		}
		for _, row := range frameList {
			m[row.Addr] = row
		}
		for _, addr := range addrs {
			_, ok := m[addr]
			if !ok {
				err = errors.New(fmt.Sprintf("关联变量%s不存在", addr))
				return
			}
		}
	}

	return
}

func Uint16sToFloat32(data []uint16, endian string) (f float32) {
	if len(data) != 2 {
		j_log.LogWarning([]interface{}{"Uint16sToFloat32 error len!=2"})
		return 0
	}
	b1 := tools.Uint16ToBytes(data[0], "big")
	b2 := tools.Uint16ToBytes(data[1], "big")
	buffer := make([]byte, 0)
	//buffer = []byte{b2[0], b2[1], b1[0], b1[1]}
	buffer = []byte{b1[0], b1[1], b2[0], b2[1]}
	if endian == "little" {
	} else {
		endian = "big"
	}
	f = tools.BytesToFloat32(buffer, endian)
	return
}

func Uint16sToFloat64(data []uint16, endian string) (f float64) {
	if len(data) != 4 {
		j_log.LogWarning([]interface{}{"Uint16sToFloat64 error len!=4"})
		return 0
	}
	b1 := tools.Uint16ToBytes(data[0], "big")
	b2 := tools.Uint16ToBytes(data[1], "big")
	b3 := tools.Uint16ToBytes(data[2], "big")
	b4 := tools.Uint16ToBytes(data[3], "big")
	buffer := make([]byte, 0)
	//buffer = []byte{b4[0], b4[1],b3[0], b3[1],b2[0], b2[1], b1[0], b1[1]}
	buffer = []byte{b1[0], b1[1], b2[0], b2[1], b3[0], b3[1], b4[0], b4[1]}
	if endian == "little" {
	} else {
		endian = "big"
	}
	f = tools.BytesToFloat64(buffer, endian)
	return
}

func Uint16sToUint32(data []uint16, endian string) (v uint32) {
	if len(data) != 2 {
		j_log.LogWarning([]interface{}{"Uint16sToUint32 error len!=2"})
		return 0
	}
	b1 := tools.Uint16ToBytes(data[0], "big")
	b2 := tools.Uint16ToBytes(data[1], "big")
	buffer := make([]byte, 0)
	//buffer = []byte{b2[0], b2[1], b1[0], b1[1]}
	buffer = []byte{b1[0], b1[1], b2[0], b2[1]}
	if endian == "little" {
	} else {
		endian = "big"
	}
	v = tools.BytesToUint32(buffer, endian)
	return
}

func Uint16sToInt32(data []uint16, endian string) (v int32) {
	if len(data) != 4 {
		j_log.LogWarning([]interface{}{"Uint16sToInt32 error len!=2"})
		return 0
	}
	tmpV := Uint16sToUint32(data, endian)
	return int32(tmpV)
}

func Uint16sToUint64(data []uint16, endian string) (v uint64) {
	if len(data) != 2 {
		j_log.LogWarning([]interface{}{"Uint16sToUint64 error len!=4"})
		return 0
	}
	b1 := tools.Uint16ToBytes(data[0], "big")
	b2 := tools.Uint16ToBytes(data[1], "big")
	b3 := tools.Uint16ToBytes(data[2], "big")
	b4 := tools.Uint16ToBytes(data[3], "big")
	buffer := make([]byte, 0)
	buffer = []byte{b1[0], b1[1], b2[0], b2[1], b3[0], b3[1], b4[0], b4[1]}
	if endian == "little" {
	} else {
		endian = "big"
	}
	v = tools.BytesToUint64(buffer, endian)
	return
}

func Uint16sToInt64(data []uint16, endian string) (v int64) {
	if len(data) != 4 {
		j_log.LogWarning([]interface{}{"Uint16sToInt32 error len!=2"})
		return 0
	}
	tmpV := Uint16sToUint64(data, endian)
	return int64(tmpV)
}

// WriteModbusPointToVariables 将modbus点位数据写入变量值
func (ppe *PPE) WriteModbusPointToVariables(slaveID uint8) (err error) {
	if ppe.ModbusServerHandler == nil {
		return errors.New("WriteModbusPointToVariables PPE设备handler为nil")
	}
	now := tools.GetNow()
	for _, row := range ppe.ModbusServerDB {
		if slaveID != row.SlaveID {
			continue
		}
		block, ok := ppe.ModbusServerHandler.DB[slaveID]
		if !ok {
			return errors.New(fmt.Sprintf("WriteModbusPointToVariables PPE设备未找到 slaveID, %d", slaveID))
		}
	loop1:
		for _, point := range row.PointBindList {
			variable, ok2 := VariablesMap.Get(point.Addr)
			if !ok2 {
				return errors.New(fmt.Sprintf("WriteModbusPointToVariables PPE设备未找到 variable, addr=%s", point.Addr))
			}
			newValue := float64(0)
			switch point.FunctionCode {
			case "01":
				if point.Length != 1 {
					continue
				}
				v := block.CoilStatus[point.StartAddr]
				if v == true {
					newValue = 1
				} else {
					newValue = 0
				}
			case "02":
				if point.Length != 1 {
					continue
				}

				v := block.InputStatus[point.StartAddr]
				if v == true {
					newValue = 1
				} else {
					newValue = 0
				}
			case "03":
				switch point.Length {
				case 1:
					v := block.HoldingRegisters[point.StartAddr]
					switch point.SpecType {
					case "bool":
						if v == 0 {
							newValue = 0
						} else {
							newValue = 1
						}
					case "uint8":
						newValue = float64(uint8(v))
					case "int8":
						newValue = float64(int8(v))
					case "uint16":
						newValue = float64(v)
					case "int16":
						newValue = float64(int16(v))
					case "uint32":
						fallthrough
					case "int32":
						fallthrough
					case "uint64":
						fallthrough
					case "int64":
						fallthrough
					case "float32":
						fallthrough
					case "float64":
						newValue = float64(v)
					}
				case 2:

					uint16s := block.HoldingRegisters[point.StartAddr : point.StartAddr+2]
					vUint32 := Uint16sToUint32(uint16s, point.Endian)
					vFloat32 := Uint16sToFloat32(uint16s, point.Endian)
					switch point.SpecType {
					case "bool":
						if vUint32 == 0 {
							newValue = 0
						} else {
							newValue = 1
						}
					case "uint8":
						newValue = float64(uint8(vUint32))
					case "int8":
						newValue = float64(int8(vUint32))
					case "uint16":
						newValue = float64(uint16(vUint32))
					case "int16":
						newValue = float64(int16(vUint32))
					case "uint32":
						newValue = float64(vUint32)
					case "int32":
						newValue = float64(int32(vUint32))
					case "uint64":
						fallthrough
					case "int64":
						newValue = float64(vUint32)
					case "float32":
						fallthrough
					case "float64":
						newValue = float64(vFloat32)
					}
				case 4:
					uint16s := block.HoldingRegisters[point.StartAddr : point.StartAddr+2]
					vUint64 := Uint16sToUint64(uint16s, point.Endian)
					vFloat64 := Uint16sToFloat64(uint16s, point.Endian)

					switch point.SpecType {
					case "bool":
						if vUint64 == 0 {
							newValue = 0
						} else {
							newValue = 1
						}
					case "uint8":
						newValue = float64(uint8(vUint64))
					case "int8":
						newValue = float64(int8(vUint64))
					case "uint16":
						newValue = float64(uint16(vUint64))
					case "int16":
						newValue = float64(int16(vUint64))
					case "uint32":
						newValue = float64(vUint64)
					case "int32":
						newValue = float64(int32(vUint64))
					case "uint64":
						newValue = float64(vUint64)
					case "int64":
						newValue = float64(int64(vUint64))
					case "float32":
						newValue = float64(float32(vFloat64))
					case "float64":
						newValue = vFloat64
					}
				}
			case "04":
				switch point.Length {
				case 1:
					v := block.InputRegister[point.StartAddr]

					switch point.SpecType {
					case "bool":
						if v == 0 {
							newValue = 0
							newValue = 0
						} else {
							newValue = 1
							newValue = 1
						}
					case "uint8":
						newValue = float64(uint8(v))
						newValue = float64(uint8(v))
					case "int8":
						newValue = float64(int8(v))
					case "uint16":
						newValue = float64(v)
					case "int16":
						newValue = float64(int16(v))
					case "uint32":
						fallthrough
					case "int32":
						fallthrough
					case "uint64":
						fallthrough
					case "int64":
						fallthrough
					case "float32":
						fallthrough
					case "float64":
						newValue = float64(v)
					}
				case 2:
					uint16s := block.InputRegister[point.StartAddr : point.StartAddr+2]
					vUint32 := Uint16sToUint32(uint16s, point.Endian)
					vFloat32 := Uint16sToFloat32(uint16s, point.Endian)

					switch point.SpecType {
					case "bool":
						if vUint32 == 0 {
							newValue = 0
						} else {
							newValue = 1
						}
					case "uint8":
						newValue = float64(uint8(vUint32))
					case "int8":
						newValue = float64(int8(vUint32))
					case "uint16":
						newValue = float64(uint16(vUint32))
					case "int16":
						newValue = float64(int16(vUint32))
					case "uint32":
						newValue = float64(vUint32)
					case "int32":
						newValue = float64(int32(vUint32))
					case "uint64":
						fallthrough
					case "int64":
						newValue = float64(vUint32)
					case "float32":
						fallthrough
					case "float64":
						newValue = float64(vFloat32)
					}
				case 4:
					uint16s := block.InputRegister[point.StartAddr : point.StartAddr+2]
					vUint64 := Uint16sToUint64(uint16s, point.Endian)
					vFloat64 := Uint16sToFloat64(uint16s, point.Endian)

					switch point.SpecType {
					case "bool":
						if vUint64 == 0 {
							newValue = 0
						} else {
							newValue = 1
						}
					case "uint8":
						newValue = float64(uint8(vUint64))
					case "int8":
						newValue = float64(int8(vUint64))
					case "uint16":
						newValue = float64(uint16(vUint64))
					case "int16":
						newValue = float64(int16(vUint64))
					case "uint32":
						newValue = float64(vUint64)
					case "int32":
						newValue = float64(int32(vUint64))
					case "uint64":
						newValue = float64(vUint64)
					case "int64":
						newValue = float64(int64(vUint64))
					case "float32":
						newValue = float64(float32(vFloat64))
					case "float64":
						newValue = vFloat64
					}
				}
			default:
				continue loop1
			}
			if variable.Value != newValue {
				//fmt.Printf("addr=%s, variable.Value=%v ,newValue=%v\n", variable.Addr, variable.Value, newValue)
				VariablesMap.PushMessageToClients([]*QueueValue{{
					Addr:       variable.Addr,
					FieldName:  variable.FieldName,
					Value:      newValue,
					SpecType:   variable.SpecType,
					CreateTime: &now,
				}})
			}
			variable.Value = newValue
		}
	}
	return
}

// WriteVariablesToModbusPoint 将变量值写入modbus点位值 (内存中)
func WriteVariablesToModbusPoint(addr string, value float64) (err error) {
	defer func() {
		if err0 := recover(); err0 != nil {
			j_log.LogError([]interface{}{"WriteVariablesToModbusPoint panic", err0})
			fmt.Println(string(debug.Stack()))
		}
	}()
	pointList, ok := ModbusValueMap.Get(addr)
	if !ok {
		//err = errors.New(fmt.Sprintf("未找到变量对应的modus server点位 addr=%s", addr))
		return
	}
	//j_log.LogInfo([]interface{}{fmt.Sprintf("--- 开始修改modbus点位 addr=%s, value=%f, len=%d", addr, value, len(pointList))})
	for _, point := range pointList {
		//j_log.LogInfo([]interface{}{fmt.Sprintf("正在写func=%s, spec_type=%s, ppe_id=%d, slave_id=%d, start_addr=%d, length=%d, endian=%v",
		//	point.FunctionCode, point.SpecType, point.PPEID, point.SlaveID, point.StartAddr, point.Length, point.Endian)})
		ppe, ok := RunningPPEMap.Get(point.PPEID)
		if !ok {
			return errors.New(fmt.Sprintf("设备未运行 ppe_id=%d", ppe.ID))
		}
		if ppe.RunningState != 2 {
			return errors.New(fmt.Sprintf("设备未运行 ppe_id=%d, %s", ppe.ID, ppe.Detail))
		}
		if ppe.ModbusServerHandler == nil {
			return errors.New(fmt.Sprintf("modbus handler is nil ppe_id=%d", ppe.ID))
		}
		slaveDB, ok := ppe.ModbusServerHandler.DB[point.SlaveID]
		if !ok {
			return errors.New(fmt.Sprintf("modbus handler db is nil ppe_id=%d, slave_id=%d", ppe.ID, point.SlaveID))
		}

		switch point.FunctionCode {
		case "01":
			if value == 0 {
				slaveDB.CoilStatus[point.StartAddr] = false
			} else {
				slaveDB.CoilStatus[point.StartAddr] = true
			}
		case "02":
			if value == 0 {
				slaveDB.InputStatus[point.StartAddr] = false
			} else {
				slaveDB.InputStatus[point.StartAddr] = true
			}
		case "03":
			switch point.Length {
			case 1:
				switch point.SpecType {
				case "bool":
					if value == 0 {
						slaveDB.HoldingRegisters[point.StartAddr] = 0
					} else {
						slaveDB.HoldingRegisters[point.StartAddr] = 1
					}
				default:
					slaveDB.HoldingRegisters[point.StartAddr] = uint16(value)
				}
			case 2:
				switch point.SpecType {
				case "uint8":
					fallthrough
				case "int8":
					fallthrough
				case "uint16":
					fallthrough
				case "int16":
					fallthrough
				case "uint32":
					fallthrough
				case "int32":
					v := uint32(value)
					buffer := tools.Uint32ToBytes(v, point.Endian)
					//fmt.Printf("value=%d, buffer=%v\n", v, buffer)
					slaveDB.HoldingRegisters[point.StartAddr] = tools.BytesToUint16(buffer[0:2], "big")
					slaveDB.HoldingRegisters[point.StartAddr+1] = tools.BytesToUint16(buffer[2:4], "big")
				case "uint64":
					fallthrough
				case "int64":
					v := uint64(value)
					buffer := tools.Uint64ToBytes(v, point.Endian)
					slaveDB.HoldingRegisters[point.StartAddr] = tools.BytesToUint16(buffer[0:2], "big")
					slaveDB.HoldingRegisters[point.StartAddr+1] = tools.BytesToUint16(buffer[2:4], "big")
					slaveDB.HoldingRegisters[point.StartAddr+2] = tools.BytesToUint16(buffer[4:6], "big")
					slaveDB.HoldingRegisters[point.StartAddr+3] = tools.BytesToUint16(buffer[6:8], "big")
				case "float32":
					v := float32(value)
					buffer := tools.Float32ToBytes4(v, point.Endian)
					slaveDB.HoldingRegisters[point.StartAddr] = tools.BytesToUint16(buffer[0:2], "big")
					slaveDB.HoldingRegisters[point.StartAddr+1] = tools.BytesToUint16(buffer[2:4], "big")
				case "float64":
					v := value
					buffer := tools.Float64ToBytes(v, point.Endian)
					slaveDB.HoldingRegisters[point.StartAddr] = tools.BytesToUint16(buffer[0:2], "big")
					slaveDB.HoldingRegisters[point.StartAddr+1] = tools.BytesToUint16(buffer[2:4], "big")
					slaveDB.HoldingRegisters[point.StartAddr+2] = tools.BytesToUint16(buffer[4:6], "big")
					slaveDB.HoldingRegisters[point.StartAddr+3] = tools.BytesToUint16(buffer[6:8], "big")
				}
			case 4:
				switch point.SpecType {
				case "uint8":
					fallthrough
				case "int8":
					fallthrough
				case "uint16":
					fallthrough
				case "int16":
					fallthrough
				case "uint32":
					fallthrough
				case "int32":
					fallthrough
				case "uint64":
					fallthrough
				case "int64":
					v := uint64(value)
					buffer := tools.Uint64ToBytes(v, point.Endian)
					slaveDB.HoldingRegisters[point.StartAddr] = tools.BytesToUint16(buffer[0:2], "big")
					slaveDB.HoldingRegisters[point.StartAddr+1] = tools.BytesToUint16(buffer[2:4], "big")
					slaveDB.HoldingRegisters[point.StartAddr+2] = tools.BytesToUint16(buffer[4:6], "big")
					slaveDB.HoldingRegisters[point.StartAddr+3] = tools.BytesToUint16(buffer[6:8], "big")
				case "float32":
					fallthrough
				case "float64":
					v := value
					buffer := tools.Float64ToBytes(v, point.Endian)
					slaveDB.HoldingRegisters[point.StartAddr] = tools.BytesToUint16(buffer[0:2], "big")
					slaveDB.HoldingRegisters[point.StartAddr+1] = tools.BytesToUint16(buffer[2:4], "big")
					slaveDB.HoldingRegisters[point.StartAddr+2] = tools.BytesToUint16(buffer[4:6], "big")
					slaveDB.HoldingRegisters[point.StartAddr+3] = tools.BytesToUint16(buffer[6:8], "big")
				}
			}
		case "04":
			switch point.Length {
			case 1:
				switch point.SpecType {
				case "bool":
					if value == 0 {
						slaveDB.InputRegister[point.StartAddr] = 0
					} else {
						slaveDB.InputRegister[point.StartAddr] = 1
					}
				default:
					slaveDB.InputRegister[point.StartAddr] = uint16(value)
				}
			case 2:
				switch point.SpecType {
				case "uint8":
					fallthrough
				case "int8":
					fallthrough
				case "uint16":
					fallthrough
				case "int16":
					fallthrough
				case "uint32":
					fallthrough
				case "int32":
					v := uint32(value)
					buffer := tools.Uint32ToBytes(v, point.Endian)
					slaveDB.InputRegister[point.StartAddr] = tools.BytesToUint16(buffer[0:2], "big")
					slaveDB.InputRegister[point.StartAddr+1] = tools.BytesToUint16(buffer[2:4], "big")
				case "uint64":
					fallthrough
				case "int64":
					v := uint64(value)
					buffer := tools.Uint64ToBytes(v, point.Endian)
					slaveDB.InputRegister[point.StartAddr] = tools.BytesToUint16(buffer[0:2], "big")
					slaveDB.InputRegister[point.StartAddr+1] = tools.BytesToUint16(buffer[2:4], "big")
					slaveDB.InputRegister[point.StartAddr+2] = tools.BytesToUint16(buffer[4:6], "big")
					slaveDB.InputRegister[point.StartAddr+3] = tools.BytesToUint16(buffer[6:8], "big")
				case "float32":
					v := float32(value)
					buffer := tools.Float32ToBytes4(v, point.Endian)
					slaveDB.InputRegister[point.StartAddr] = tools.BytesToUint16(buffer[0:2], "big")
					slaveDB.InputRegister[point.StartAddr+1] = tools.BytesToUint16(buffer[2:4], "big")
				case "float64":
					v := value
					buffer := tools.Float64ToBytes(v, point.Endian)
					slaveDB.InputRegister[point.StartAddr] = tools.BytesToUint16(buffer[0:2], "big")
					slaveDB.InputRegister[point.StartAddr+1] = tools.BytesToUint16(buffer[2:4], "big")
					slaveDB.InputRegister[point.StartAddr+2] = tools.BytesToUint16(buffer[4:6], "big")
					slaveDB.InputRegister[point.StartAddr+3] = tools.BytesToUint16(buffer[6:8], "big")
				}
			case 4:
				switch point.SpecType {
				case "uint8":
					fallthrough
				case "int8":
					fallthrough
				case "uint16":
					fallthrough
				case "int16":
					fallthrough
				case "uint32":
					fallthrough
				case "int32":
					fallthrough
				case "uint64":
					fallthrough
				case "int64":
					v := uint64(value)
					buffer := tools.Uint64ToBytes(v, point.Endian)
					slaveDB.InputRegister[point.StartAddr] = tools.BytesToUint16(buffer[0:2], "big")
					slaveDB.InputRegister[point.StartAddr+1] = tools.BytesToUint16(buffer[2:4], "big")
					slaveDB.InputRegister[point.StartAddr+2] = tools.BytesToUint16(buffer[4:6], "big")
					slaveDB.InputRegister[point.StartAddr+3] = tools.BytesToUint16(buffer[6:8], "big")
				case "float32":
					fallthrough
				case "float64":
					v := value
					buffer := tools.Float64ToBytes(v, point.Endian)
					slaveDB.InputRegister[point.StartAddr] = tools.BytesToUint16(buffer[0:2], "big")
					slaveDB.InputRegister[point.StartAddr+1] = tools.BytesToUint16(buffer[2:4], "big")
					slaveDB.InputRegister[point.StartAddr+2] = tools.BytesToUint16(buffer[4:6], "big")
					slaveDB.InputRegister[point.StartAddr+3] = tools.BytesToUint16(buffer[6:8], "big")
				}
			}
		}
	}

	return
}
